using System;
using System.Collections.Generic;
using System.Text;

namespace Ops.Mpc.ExampleApplication.Web
{

    public class RandomProvider
    {
        private Random _Random;
        
        #region Constructor

        public RandomProvider()
        {
            Reset();
        }
        public void Reset()
        {
            _Random = new Random();
        }

        #endregion


        /// <summary>
        /// Returns double in the range [0, 1)
        /// </summary>
        public double Next()
        {
            return _Random.NextDouble();
        }

        /// <summary>
        /// Returns true or false randomly.
        /// </summary>
        public bool NextBoolean()
        {
            return (bool)(_Random.Next(0, 2) == 0);
        }

        /// <summary>
        /// Returns double in the range [0, 1)
        /// </summary>
        public double NextDouble()
        {
            return _Random.NextDouble();
        }

        /// <summary>
        /// Returns Int16 in the range [min, max)
        /// </summary>
        public Int16 Next(Int16 min, Int16 max)
        {
            if (max <= min)
            {
                string message = "Max must be greater than min.";
                throw new ArgumentException(message);
            }
            double rn = (max * 1.0 - min * 1.0) * _Random.NextDouble() + min * 1.0;
            return Convert.ToInt16(rn);
        }

        /// <summary>
        /// Returns Int32 in the range [min, max)
        /// </summary>
        public int Next(int min, int max)
        {
            return _Random.Next(min, max);
        }

        /// <summary>
        /// Returns Int64 in the range [min, max)
        /// </summary>
        public Int64 Next(Int64 min, Int64 max)
        {
            if (max <= min)
            {
                string message = "Max must be greater than min.";
                throw new ArgumentException(message);
            }

            double rn = (max * 1.0 - min * 1.0) * _Random.NextDouble() + min * 1.0;
            return Convert.ToInt64(rn);
        }

        /// <summary>
        /// Returns float (Single) in the range [min, max)
        /// </summary>
        public float Next(float min, float max)
        {
            if (max <= min)
            {
                string message = "Max must be greater than min.";
                throw new ArgumentException(message);
            }

            double rn = (max * 1.0 - min * 1.0) * _Random.NextDouble() + min * 1.0;
            return Convert.ToSingle(rn);
        }

        /// <summary>
        /// Returns double in the range [min, max)
        /// </summary>
        public double Next(double min, double max)
        {
            if (max <= min)
            {
                string message = "Max must be greater than min.";
                throw new ArgumentException(message);
            }

            double rn = (max - min) * _Random.NextDouble() + min;
            return rn;
        }

        /// <summary>
        /// Returns DateTime in the range [min, max)
        /// </summary>
        public DateTime Next(DateTime min, DateTime max)
        {
            if (max <= min)
            {
                string message = "Max must be greater than min.";
                throw new ArgumentException(message);
            }
            long minTicks = min.Ticks;
            long maxTicks = max.Ticks;
            double rn = (Convert.ToDouble(maxTicks)
               - Convert.ToDouble(minTicks)) * _Random.NextDouble()
               + Convert.ToDouble(minTicks);
            return new DateTime(Convert.ToInt64(rn));
        }

        /// <summary>
        /// Returns TimeSpan in the range [min, max)
        /// </summary>
        public TimeSpan Next(TimeSpan min, TimeSpan max)
        {
            if (max <= min)
            {
                string message = "Max must be greater than min.";
                throw new ArgumentException(message);
            }

            long minTicks = min.Ticks;
            long maxTicks = max.Ticks;
            double rn = (Convert.ToDouble(maxTicks) - Convert.ToDouble(minTicks)) * _Random.NextDouble() + Convert.ToDouble(minTicks);
            return new TimeSpan(Convert.ToInt64(rn));
        }

        /// <summary>
        /// Returns a random enum value 
       /// </summary>
        public object NextEnum(Type enumType)
        {
            object[] values = (object[])Enum.GetValues(enumType);
            int randomIndex = Next(0, values.Length);
            return values[randomIndex];
        }

        public char NextChar(int min, int max)
        {
            if (max <= min)
            {
                string message = "Max must be greater than min.";
                throw new ArgumentException(message);
            }

            return Convert.ToChar((int)Next(min, max));
        }

        public char NextChar(char[] characterset)
        {
            if (characterset.Length == 0)
            {
                string message = "Supplied Character Set must contain at least 1 character";
                throw new ArgumentException(message);
            }

            return characterset[Next(0, characterset.Length - 1)];
        }


        public string NextString(int minLength, int maxLength, char[] characterset)
        {
            if (maxLength < minLength)
            {
                string message = "Max Length must be greater than min. Length";
                throw new ArgumentException(message);
            }
            StringBuilder sb = new StringBuilder();
            int length = (int)Next(minLength, maxLength + 1);

            for (int i = 0; i < length; i++)
            {
                sb.Append(NextChar(characterset));
            }

            return sb.ToString();
        }

    }
   }
